package core

import (
	"context"
	"energy-amiot-platform/model/dbspo"
	"errors"
	"fmt"
	"log/slog"
	"time"

	"github.com/go-gormigrate/gormigrate/v2"
	slogGorm "github.com/orandin/slog-gorm"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

var (
	DATABASE dbs
)

type dbs struct {
	gdb *gorm.DB
}

// 写入默认配置
func (d *dbs) dc() {
	viper.SetDefault("database.host", "127.0.0.1")
	viper.SetDefault("database.port", 5432)
	viper.SetDefault("database.dbname", "amiot")
	viper.SetDefault("database.user", "amiot_user")
	viper.SetDefault("database.password", "miot_password")
	viper.SetDefault("database.sslmode", "disable")
	viper.SetDefault("database.timezone", "Alias/Shanghai")
	viper.SetDefault("database.timeout", 2)
}

func (d *dbs) setup() {
	dbtype := viper.Get("database.type")
	user := viper.Get("database.user")
	password := viper.GetString("database.password")
	host := viper.GetString("database.host")
	port := viper.GetUint16("database.port")
	dbName := viper.GetString("database.dbname")
	sslmode := viper.GetString("database.sslmode")
	timezone := viper.GetString("database.timezone")
	timeout := viper.GetInt("database.timeout")

	var dsn string
	var db *gorm.DB
	var err error
	logger := slogGorm.New(
		slogGorm.WithLogger(LOG.Logger),
		slogGorm.WithSlowThreshold(1000*time.Millisecond),
		slogGorm.WithTraceAll(),
	)

	switch dbtype {
	case "postgresql":
		dsn = fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=%s",
			host, user, password, dbName, port, sslmode, timezone)
		db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
			NowFunc: func() time.Time { return time.Now() },
			Logger:  logger,
		})
	case "mysql":
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeou%d", user, password, host, port, dbName, timeout)
		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
			NowFunc: func() time.Time { return time.Now() },
			Logger:  logger,
		})
	default:
		panic(errors.New("不支持的数据类型"))
	}

	if err != nil {
		panic(err)
	}

	db = db.WithContext(context.Background())
	sqlDb, err := db.DB()
	if err != nil {
		panic(err)
	}

	err = sqlDb.Ping()
	if err != nil {
		panic(err)
	}

	d.gdb = db
	slog.Info("database连接成功")
}

func (d *dbs) migrate() {
	m := gormigrate.New(d.Cur(), gormigrate.DefaultOptions, []*gormigrate.Migration{
		{
			ID: "20231214",
			Migrate: func(tx *gorm.DB) error {
				return tx.AutoMigrate(&dbspo.Company{}, &dbspo.Product{})
			},
			Rollback: func(tx *gorm.DB) error {
				return nil
			},
		},
		{
			ID: "20231215",
			Migrate: func(tx *gorm.DB) error {
				return tx.AutoMigrate(&dbspo.Model{})
			},
			Rollback: func(tx *gorm.DB) error {
				return nil
			},
		},
		{
			ID: "20231216",
			Migrate: func(tx *gorm.DB) error {
				return tx.AutoMigrate(&dbspo.Device{})
			},
			Rollback: func(tx *gorm.DB) error {
				return nil
			},
		},
		{
			ID: "20231221",
			Migrate: func(tx *gorm.DB) error {
				return tx.AutoMigrate(&dbspo.MqttSender{})
			},
			Rollback: func(tx *gorm.DB) error {
				return nil
			},
		},
		{
			ID: "20231222",
			Migrate: func(tx *gorm.DB) error {
				return tx.AutoMigrate(&dbspo.App{})
			},
			Rollback: func(tx *gorm.DB) error {
				return nil
			},
		},
	})

	if err := m.Migrate(); err != nil {
		slog.Error("Could not migrate", err)
	}
	slog.Info("Migration did run successfully")
}

func (d *dbs) Cur() *gorm.DB {
	return d.gdb
}
